<?php
/**
 * 全局日志记录行为
 * @author xiejianwen@star-net.cn
 * @copyright © ktvme. All Rights Reserved.
 * @version $Id: AdLog.php 437 2017-12-12 02:46:04Z chenjunliang $
 */

namespace app\common\behavior;

use \think\Log;
use \think\Request;
use utils\HeaderUtils;
use \think\Response;
use \think\Db;

class AdLog {

    /**
     * 请求对象
     * @var Request
     */
    public $request;
    protected $param = '';
    /**
     * AdLog constructor.
     */
    public function __construct() {
        $this->request = Request::instance();
        $this->param = $this->request->param();
    }

    /**
     * 控制器开始标签位, 记录请求基本信息
     */
    public function action_begin($params) {
        //监听数据库sql执行，可通过配置文件关闭
        Db::listen(function($sql, $time, $explain) {
            $sqlArr    = explode(" ", $sql);
            $sqlLogArr = [
                'select',
                'update',
                'insert'
            ];

            if(count($sqlArr) > 0 && in_array(strtolower($sqlArr[0]), $sqlLogArr)) {
                $sqlLog = $sql . '[t=' . $time . ']';
                $sqlLog .= $explain ? '[e=' . json_encode($explain) . ']' : '';
                Log::record($sqlLog, 'elk_more_info', 'sql');
            }
        });

        //收到请求时间,精确到毫秒级,格式为 yyyy-mm-dd hh:mm:ss.zzz
        list($usec, $sec) = explode(" ", microtime());
        $log['request_time'] = date('Y-m-d H:i:s.') . substr($usec, 2, 3);
        //请求唯一ID,用于定位请求链路
        $log['request_id'] = $this->createSerializeId();
        //项目名称或者业务名称，用于区分不同业务，业务方接入前事先与运维平台沟通并分配
        $log['project'] = 'adadmin';
        //接口模块标识
        $log['model'] = $this->request->module();
        //接口协议标识
        $log['protocol'] = '/' . $this->request->controller() . '/' . $this->request->action();
        //接口请求地址
        $log['request_url'] = $this->request->url(true);
        //请求参数
        $log['parameter'] = json_encode($this->param, JSON_UNESCAPED_UNICODE);
        //请求头
        $log['header'] = json_encode($this->request->header(), JSON_UNESCAPED_UNICODE);
        //客户端User-Agent信息
        $log['device'] = implode('/', HeaderUtils::getUserAgentArr());
        //接口请求用户标识
        $log['customerid'] = intval($this->request->get('customerid') ? $this->request->get('customerid') : '0');
        //接口请求商家code标识
        $log['companycode'] = $this->request->get('companycode') ? $this->request->get('companycode') : '-';
        //客户端ip
        $log['client_ip'] = $this->request->ip();

        Log::record($log, 'elk');
    }

    /**
     * 记录返回值等信息
     * @param $params response对象
     */
    public function response_end($response) {
        $elk = Log::getLog('elk');
        //扩展字段，存储自定义数据
        $elkMoreInfo = Log::getLog('elk_more_info');

        $elk['more_info'] = $elkMoreInfo?$elkMoreInfo:[];
        //接口响应时间，单位为秒，精确到毫秒
        $fRunTime = microtime(true) - $this->request->server('REQUEST_TIME_FLOAT');
        $elk['response_time'] = round($fRunTime, 5);

        //是ajax请求并且返回值是json格式才记录返回值，不然会把html模版都记录进去
        //为了兼容接口 改成 是json格式接存储日志
        $responseContent = $response->getContent();
        if(!is_null(json_decode($responseContent))) {
            $elk['response'] = $responseContent;
        }
        //用于标识日志类型，默认填写"km"
        $elk['label'] = 'km';
        //用于标识日志类型，默认填写"km"，否则填写自定义的标签，该标签需要与运维平台事先沟通，避免冲突
        $status = config('elk_status');
        if($status) {
            $elk['status'] = intval($status);
        } else {
            $elk['status'] = 0;
        }

        Log::record($elk, 'elk');
        Log::save();
    }

    /**
     * 创建唯一标识
     * @param string $prefix 请求标识前缀
     * @return string 请求标识
     */
    public function createSerializeId($prefix = null) {
        $uuid = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : "";
        $uuid .= isset($_SERVER['REMOTE_PORT']) ? $_SERVER['REMOTE_PORT'] : "";
        if(isset($_SERVER['HTTP_USER_AGENT'])) {
            $uuid .= $_SERVER['HTTP_USER_AGENT'];
        }
        $uuid .= isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : "";

        return hash('ripemd128', uniqid('', true) . md5($prefix . $uuid));
    }
}